package com.blue.integration.spring.redis;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.util.Assert;

/**
 * Hash缓存
 *
 * @author zhengjin
 * @since 1.0 2018年06月23日
 */
public abstract class AbstractHashCache<T>
{
	//private static Logger logger = LoggerFactory.getLogger(AbstractHashCache.class);
	public static final String ID = "id_";
	public static final String CODE = "code_";
	public static final String LIST_ALL = "list_all";
	public static final String LIST = "list_";
	public static final String PARENT_LIST = "parent_list_";

	@Autowired
	protected RedisCache redisCache;

	protected Class<T> cacheClazz;

	@SuppressWarnings("unchecked")
	public AbstractHashCache()
	{
		Type[] types = ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments();
		cacheClazz = (Class<T>) types[0];
	}

	/**
	 * 删除缓存
	 */
	public final void delete()
	{
		String key = this.getKey();
		redisCache.delete(key);
	}

	/**
	 * 从缓存中获取单个对象
	 *
	 * @param name 缓存中的键名称
	 * @return 单个对象
	 */
	@SuppressWarnings("unchecked")
	protected final T get(String name)
	{
		Assert.hasText(name, "Hash 名称不能为空");
		BoundHashOperations<String, String, Object> hashOps = getHashOps();
		T obj = (T) hashOps.get(name);
		return obj;
	}

	/**
	 * 从缓存中获取对象列表
	 *
	 * @param name 缓存中的键名称
	 * @return 对象列表
	 */
	@SuppressWarnings("unchecked")
	protected final List<T> list(String name)
	{
		Assert.hasText(name, "Hash 名称不能为空");
		BoundHashOperations<String, String, Object> hashOps = getHashOps();
		List<T> list = (List<T>) hashOps.get(name);
		return list;
	}

	/**
	 * 获取Hash操作
	 *
	 * @return Hash操作
	 */
	protected final BoundHashOperations<String, String, Object> getHashOps()
	{
		this.initCache();
		String key = this.getKey();
		return redisCache.hashOps(key);
	}

	/**
	 * 初始化缓存
	 */
	protected final void initCache()
	{
		String key = this.getKey();
		if (!redisCache.exist(key))
		{
			redisCache.lock(key);
			try
			{
				if (!redisCache.exist(key))
				{
					BoundHashOperations<String, String, Object> hashOps = redisCache.hashOps(key);
					this.initCacheItem(hashOps);
					redisCache.expire(key, this.getExpireHour(), TimeUnit.HOURS);
				}
			}
			finally
			{
				redisCache.unlock(key);
			}
		}
	}

	/**
	 * 返回过期时间，默认1小时
	 */
	protected int getExpireHour()
	{
		return 1;
	}

	/**
	 * 初始化缓存数据
	 */
	protected abstract void initCacheItem(BoundHashOperations<String, String, Object> hashOps);

	/**
	 * 获取键
	 */
	protected abstract String getKey();

}
